#pragma once

#include "ColligereDatabaseItemBase.hpp"
#include "ColligereDatabaseEventBase.hpp"

namespace col 
{

/*! @brief A Base class for a database handler.
 *
 * The database handler is responsible for querying, adding, updating and 
 * deleting items from the database.
 **/
class DatabaseHandlerBase : public wxEvtHandler
{
public:
	DatabaseHandlerBase();
	virtual ~DatabaseHandlerBase();

	virtual void Open ( const wxString &rInputFile,
		wxUint32 syncType, bool autoVacuum );
	virtual void Close();
	virtual void Save ( const wxString &rToFile = wxString(),
		wxUint32 compressLevel = 9 );

	virtual void SetParentEvtHandler ( wxEvtHandler *pEvt  );

	virtual void QueryAllItems ( bool forceQueryDatabase = false ) = 0;
	virtual void AddItem ( const DatabaseItemBase &rItem ) = 0;
	virtual void UpdateItem ( const DatabaseItemBase &rItem ) = 0;

	const wxString &GetInputFile() const;
	const wxString &GetBufferFile() const;
	const wxUint32 GetId() const;
	virtual wxUint32 GetTypeId() const = 0;

	wxUint32 GetItemCount() const;
	const DatabaseItemBaseDeque &GetItems() const;

	virtual const DatabaseItemBase *FindItem ( DatabaseItemId id ) const;
	virtual DatabaseItemBase *FindItem ( DatabaseItemId id );

	virtual bool IsQueryable();
	/*! @brief Returns true if a database has been successfully opened.
	 *
	 * The member variable mInputFile will contain a valid filename
	 * only if the opening succeeded.
	 **/
	virtual bool IsOpened() const;

	struct SearchFlag
	{
		enum
		{
			CaseSensitive = 1 << 1,
			UseRegEx = 1 << 2
		};
	};

	//! http://www.sqlite.org/pragma.html
	struct SyncType
	{
		enum
		{
			// Do not alter the order.
			Off = 0,
			Normal,
			Full
		};
	};
	
	virtual const DatabaseItemBaseDeque Search ( const wxString &rTerm,
		wxUint32 flags ) const = 0;

	virtual const DatabaseItemBaseDeque SearchFromColumn ( const wxString &rTerm,
		bool caseSensitive, const DatabaseTable &rTable,
		const Column &rColumn ) const = 0;
	
	virtual const DatabaseItemBaseDeque SearchFromColumn ( const wxRegEx &rRe,
		const DatabaseTable &rTable, const Column &rColumn ) const = 0;

	virtual void DeleteItem ( const DatabaseItemBase &rItem ) = 0;

	virtual wxUint32 GetChangedItemCount() const = 0;

	//! Returns the number of rows in the table 'rTable'.
	wxUint32 GetRowCount ( const DatabaseTable &rTable );

	static void EnableSqlDebugLog ( bool enable = true );
protected:
	struct MetadataTable
	{
		enum
		{
			AppVersionCreate = 1,
			AppVersionUpdate,
			DatabaseTypeId
		};
	};

	virtual void RunQuery ( const wxString &rQuery );
	virtual void CommitChanges() = 0;
	virtual void CreateTables();
	virtual void InsertMetadata();
	virtual void UpdateMetadata();

	virtual wxSQLite3ResultSet RunQueryWithResults ( const wxString &rQuery );
	virtual bool IsTableStructureCreated();
	virtual DatabaseItemId CommitItem ( DatabaseItemBase &rItem );


	/*! @brief The layout parent for this database.
	 *
	 * Used to post database events. Must not be NULL when an database is opened.
	 **/
	wxEvtHandler *mpParentEvtHandler;
	
	/*! @brief The database layer instance for this database.
	 *
	 * Acts as an interface to the underlying SQLite3 C-API.
	 **/
	wxSQLite3Database mDatabaseLayer;
	
	/*! @brief A path to the actual input file (i.e. the one that was selected by the user).
	 *
	 * This file is written only when the user commits changes.
	 **/
	wxString mInputFile;
	//! A path to a buffer file to which all changes are committed.
	wxString mBufferFile;
	
	/*! @brief The unique ID for this database.
	 *
	 * Must be > 0.
	 **/
	wxUint32 mId;

	DatabaseItemBaseDeque mItemList;

	static wxString msMetadataTableName;
	static bool msEnableSqlDebugLog;
private:
	void PostDatabaseEvent ( wxEventType evtType );

	static DatabaseTable msMetadataTable;
};

}